
/*
* Source: getch.c
* Autor: Jorge Pereira
* Data:  Tue Jul 29 09:35:42 BRT 2008
* Desc:  Implementacao da funcao getch() no Linux,
* podendo ser feito leitura de um unico byte por vez.
*
*/
	
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>
#include <termio.h>


struct termio old_tty;
struct termio new_tty;
int runed = 0;


#ifdef getch
#undef getch
#endif
typedef unsigned int keybd_t;

void getch_exit(void){
	ioctl(STDIN_FILENO, TCSETA, &old_tty);
}


void prepare_fd_stdin(void)
{
	if (! runed) {
		runed = 1;
		atexit(getch_exit);
		if (ioctl(STDIN_FILENO, TCGETA, &old_tty) < 0)
		{	
			fprintf(stderr,"Port ioctl(TCGETA) it's failed, exiting...\n");
			exit(EXIT_FAILURE);
		}
	}
	new_tty = old_tty;
	new_tty.c_lflag &= ~(ICANON | ECHO);
	new_tty.c_cc[4]  = 01;

	if (ioctl(STDIN_FILENO, TCSETA, &new_tty) < 0)
	{
		fprintf(stderr,"Port ioctl(TCSETA) it's failed, exiting...\n");
		exit(EXIT_FAILURE);
	}
}

int kbhit(void)
{

	int	key = 0;
	fd_set readfds;
	struct timeval tv = { 0, 0 };
	prepare_fd_stdin();
	



	FD_ZERO(&readfds);
	FD_SET(STDIN_FILENO, &readfds);
	
	select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv);

	if (FD_ISSET(STDIN_FILENO, &readfds))
		key = 1;


	return key;
}
int get_stdin(){
	return STDIN_FILENO;
}

keybd_t getch (void)
{

	key_t	key = 0;

	prepare_fd_stdin();

	if(read(STDIN_FILENO, &key, sizeof(key)) < 0)
	{
		fprintf(stderr,"Problems in read()\n");
		exit(EXIT_FAILURE);
	}


	return key;
}


#if defined(RUN_MAIN)
int
main (void)
{
	keybd_t key;

	printf ("(*) Teste para funcao getch(), pressione  para sair!\n");

	while ((key = getch()) != 0x1b)
	{
		char ch = (key >= 'a' && key <= 'z') ||
		(key >= 'A' && key <= 'Z') ||
		(key >= '0' && key <= '9') ? key: ' ';

		printf (" -> key char(%c) hex(0x%08x) dec(%d)\n", ch, key, key);
	}

	printf ("(*) Saindo...\n");

	return EXIT_SUCCESS;
}
#endif
/* getch.c - end */
